using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace ch.ethz.ssh2.channel
{

    /// <summary> LocalAcceptThread.
    /// 
    /// </summary>
    /// <author>  Christian Plattner
    /// </author>
    /// <version>  2.50, 03/15/10
    /// </version>
    public class LocalAcceptThread : IChannelWorkerThread
    {
        internal ChannelManager cm;
        internal System.String host_to_connect;
        internal int port_to_connect;

        //UPGRADE_NOTE: Final was removed from the declaration of 'ss '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
        internal System.Net.Sockets.TcpListener ss;

        public LocalAcceptThread(ChannelManager cm, int local_port, System.String host_to_connect, int port_to_connect)
        {
            this.cm = cm;
            this.host_to_connect = host_to_connect;
            this.port_to_connect = port_to_connect;

            System.Net.Sockets.TcpListener temp_tcpListener;
            temp_tcpListener = new System.Net.Sockets.TcpListener(System.Net.Dns.GetHostByName(System.Net.Dns.GetHostName()).AddressList[0], local_port);
            temp_tcpListener.Start();
            ss = temp_tcpListener;
        }

        public LocalAcceptThread(ChannelManager cm, IPEndPoint localAddress, System.String host_to_connect, int port_to_connect)
        {
            this.cm = cm;
            this.host_to_connect = host_to_connect;
            this.port_to_connect = port_to_connect;

            ss = new TcpListener(localAddress);
        }

        public void Run()
        {
            try
            {
                cm.registerThread(this);
            }
            catch (System.IO.IOException e)
            {
                stopWorking();
                return;
            }

            while (true)
            {
                System.Net.Sockets.TcpClient client = null;

                try
                {
                    client = ss.AcceptTcpClient();
                }
                catch (System.IO.IOException e)
                {
                    stopWorking();
                    return;
                }

                Channel cn = null;
                Thread r2l = null;
                Thread l2r = null;

                try
                {
                    /* This may fail, e.g., if the remote port is closed (in optimistic terms: not open yet) */

                    //UPGRADE_ISSUE: Method 'java.net.Socket.getInetAddress' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javanetSocketgetInetAddress'"
                    //UPGRADE_ISSUE: Method 'java.net.Socket.getPort' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javanetSocketgetPort'"
                    cn = cm.openDirectTCPIPChannel(host_to_connect, port_to_connect, ((IPEndPoint)client.Client.LocalEndPoint).Address.ToString(), ((IPEndPoint)client.Client.LocalEndPoint).Port);
                }
                catch (System.IO.IOException e)
                {
                    /* Simply close the local socket and wait for the next incoming connection */

                    try
                    {
                        client.Close();
                    }
                    catch (System.IO.IOException ignore)
                    {
                    }

                    continue;
                }

                try
                {
                    r2l = new Thread(new ThreadStart(new StreamForwarder(cn, null, null, cn.stdoutStream, client.GetStream(), "RemoteToLocal").Run));
                    l2r = new Thread(new ThreadStart(new StreamForwarder(cn, r2l, client, client.GetStream(), cn.stdinStream, "LocalToRemote").Run));
                }
                catch (System.IO.IOException e)
                {
                    try
                    {
                        /* This message is only visible during debugging, since we discard the channel immediatelly */
                        //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
                        cn.cm.closeChannel(cn, "Weird error during creation of StreamForwarder (" + e.Message + ")", true);
                    }
                    catch (System.IO.IOException ignore)
                    {
                    }

                    continue;
                }

                r2l.IsBackground = true;
                l2r.IsBackground = true;
                r2l.Start();
                l2r.Start();
            }
        }

        public virtual void stopWorking()
        {
            try
            {
                /* This will lead to an IOException in the ss.accept() call */
                ss.Stop();
            }
            catch (System.IO.IOException e)
            {
            }
        }
    }
}